#include "Lily_help.h"
#include <math.h>

typedef char *str;
typedef struct
{
	Var iter_field;
	Li_List for_cmd_lines;
	float end_val, step_val;
	int32_t now_at;
	unsigned char var_at;
	char need_delete_field;
	char be_greater;

} ForItem_def;
typedef struct
{
	Li_List cmd_lines;
	int32_t loop_count, now_at;
} LoopItem_def;

#define for_stack_len 4
#define loop_stack_len 4
ForItem_def for_area_stack[for_stack_len];
unsigned char for_stack_count = 0;
LoopItem_def loop_area_stack[loop_stack_len];
unsigned char loop_stack_count = 0;

Li_List for_cmd_lines = NULL;
float *end_val, *step_val;
int32_t *now_at;
char *be_greater;
char *need_delete_field;
Var iter_field = NULL;
int32_t var_at = 0;
Li_String scopy = NULL;
unsigned char wait_for_end_count = 0;
char in_filling = 0;

Li_List loop_cmd_lines = NULL;
int32_t *loop_count = 0, *loop_now_at = 0;
char loop_in_filling = 0;

int32_t meet_current_exp = 0;
typedef struct
{
	int32_t now_at;
	Li_List cmd_lines;
} For_enrty_t;

#define if_stack_len 4
For_enrty_t if_area_stack[if_stack_len];
unsigned char if_stack_count = 0;
Li_List if_cmd_lines = NULL;
int32_t *if_now_at = NULL;
char if_in_filling = 0;
unsigned char recive_done = 0;

int32_t end_for(void);
int32_t do_for_loop(void);
char *get_cmd_line_at(Li_List, int32_t);
int32_t hijackor_for_end(int32_t n, char **args);
void update_for_area(void);
void release_all(void);

int32_t hijackor_loop_end(int32_t n, char *args[]);
int32_t do_loop_loop(void);
void end_loop(void);
void update_loop_area(void);

int32_t hijackor_if_end(int32_t n, char *args[]);
int32_t do_if_loop(void);
void end_if(void);
void update_if_area(void);

int32_t go_break(void);
int32_t go_continue(void);

int32_t hijackor_while_end(int32_t n, char *args[]);
int32_t do_while_loop(void);

void release_all_if(void);

// new:
// items, iter_field_index, for_cmd_lines,iter_field_name
int32_t cmd_for_start(int32_t n, char *args[]) // call by lily_do
{
	if (n < 2)
		return -1;
	joint_args(n - 1, args + 1);							  // i=1:0.1:3
	Li_List items = str_split_by_str(args[1], (char *)" =:"); // new [ i 1 0.1 3]

	args = (char **)(items->content);
	float start, step, endv;
	char be_greater_;
	char need_delete_field_;

	if (items->count < 3)
	{
		delete_list(items);
		li_error("bad arguments", -__LINE__);
	}
	Lily_List numbers_a;
	numbers_a.content = (char *)(args + 1);
	numbers_a.count = items->count - 1;
	Li_List numbers = _values_of_vars(&numbers_a); // new
	if (numbers == NULL)
	{
		delete_list(items);
		li_error("bad arguments", -__LINE__);
	}
	float *nums = list_content(numbers, float);

	if (numbers->count == 3)
	{
		step = nums[1];
		endv = nums[2];
	}
	else if (numbers->count == 2)
	{
		step = 1.0f;
		endv = nums[1];
	}
	else
	{
		delete_list(numbers);
		delete_list(items);
		li_error("bad arguments", -__LINE__);
	}
	start = nums[0];
	delete_list(numbers);
	if (start < endv && step > 0.0f)
	{
		be_greater_ = 1;
	}
	else if (start > endv && step < 0)
	{
		be_greater_ = 0;
	}
	else
	{
		delete_list(items);
		li_error("bad step", -2);
	}

	int32_t iter_field_index = search_var_in_Lily_ui(args[0]);
	need_delete_field_ = 0;
	if (iter_field_index < 0)
	{
		iter_field_index = public_a_new_var(args[0], 'f', to_voidf(start));
		need_delete_field_ = 1;
		var_at = 0;
		if (iter_field_index < 0) // not create new field
		{
			delete_list(items);
			_fun_exit();
			lily_out("\aerror -12:build new field failed\n");
			li_error("apply filed", -__LINE__);
		}
		iter_field = li_vars + iter_field_index;
	}
	else
	{
		iter_field = li_vars + iter_field_index;
		var_at = _ebrace_value_from_string(args[0]);
		if (var_at < 0)
		{
			var_at = 0;
		}

		switch (iter_field->type)
		{
		case 'f':
			set_value_of_var(iter_field, var_at, to_voidf(start));
			break;
		case 'd':
		case 'c':
			set_value_of_var(iter_field, var_at, to_void((int32_t)start));
			break;
		default:
			delete_list(items);
			// li_error("bad var", -5);
			break;
		}
	}

	delete_list(items);
	add_hijack(hijackor_for_end);
	in_filling = 1;
	for_cmd_lines = new_list(sizeof(str), 4);
	// create successful
	// push it to stack

	ForItem_def *area = for_area_stack + for_stack_count;
	area->iter_field = iter_field;
	area->var_at = var_at;
	area->for_cmd_lines = for_cmd_lines;
	// area->start_val = start;
	area->end_val = endv;
	area->step_val = step;
	area->now_at = 0;
	area->need_delete_field = need_delete_field_;
	area->be_greater = be_greater_;

	for_stack_count++;
	update_for_area();

	wait_for_end_count = 1;
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial
	return 0;
}
// new si = for_cmd_lines.contnet[i]
int32_t hijackor_for_end(int32_t n, char **args)
{
	char *s = args[0];
	if (str_equal(args[0], "for") || str_equal(args[0], "loop") || str_equal(args[0], "if") || str_equal(args[0], "while"))
	{
		wait_for_end_count++;
	}
	else if (strcmp(s, "end") == 0)
	{
		wait_for_end_count--;
		if (wait_for_end_count == 0)
		{
			// news
			_lily_is_busy = 1;

			in_filling = 0;
			add_listener(do_for_loop);
			*now_at = 0;
			str s = get_cmd_line_at(for_cmd_lines, *now_at);
			// note here hijackor_if_end() hijacked lily, so stack_top==1
			if (_stack_top == 1 && str_equal(s, "break"))
			{
				if (go_break() < 0)
				{
					lily_out("[for.c/hijackor_for_end at 229]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			else if (_stack_top == 1 && str_equal(s, "continue"))
			{
				if (go_continue() < 0)
				{
					lily_out("[for.c/hijackor_for_end at 238]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			tp_addTaskArg((TasksArg_def)lily_do, s);
#ifdef for_show_detial
			lily_out(s);
			lily_out(">");
#endif // for_show_detial

			return Lily_cmd_do_not_notify; // free hijack, not notify
		}
	}
	// save the cmd lines
	char *si = new_string_by(s);
	if (si == NULL || li_add(for_cmd_lines, si) < 0)
	{
		lily_out("loop error:mry\n");
		_fun_exit();
		return -4;
	}
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial

	return KeepHijack; // notify
}

int32_t do_for_loop()
{

	if (in_filling)
	{
		for_stack_count--; // switch last area
		update_for_area();
	}

	if (++*now_at >= for_cmd_lines->count)
	{
		float start_val = 0.0f;
		int32_t vi;
		*now_at = 0;
		// *start_val += *step_val;
		switch (iter_field->type)
		{
		case 'f':
			assign_f_from_void(start_val, get_value_of_var(iter_field, var_at));
			start_val += *step_val;
			set_value_of_var(iter_field, var_at, to_voidf(start_val));
			// *(float *)(iter_field->ref) += *step_val;
			// start_val = *(float *)(iter_field->ref);
			break;
		case 'd':
		case 'c':
			vi = (int32_t)get_value_of_var(iter_field, var_at);
			vi += *step_val; // abs(step_val)>1
			if (set_value_of_var(iter_field, var_at, to_void(vi)) < 0)
			{
				lily_out("[for_loop.c/do_for_loop]:assign failed");
			}

			// *(int32_t *)(iter_field->ref) += *step_val;
			start_val = vi; //*(int32_t *)(iter_field->ref);
			break;

		default:
			break;
		}

		if ((*be_greater && start_val >= *end_val) || (!*be_greater && start_val <= *end_val)) // iteration end
		{
			end_for();
			return 0;
		}
	}

	str s = get_cmd_line_at(for_cmd_lines, *now_at);
	if (in_filling)
	{
		for_stack_count++;
		update_for_area(); // switch back
	}

	if (!_stack_top && str_equal(s, "break"))
	{
		if (go_break() < 0)
		{
			lily_out("[for.c/do_for_loop at 307]:unknown");
		}
		return 0;
	}
	else if (!_stack_top && str_equal(s, "continue"))
	{
		if (go_continue() < 0)
		{
			lily_out("[for.c/hijackor_for_end at 229]:unknown");
		}
		return 0;
	}

	// addTaskArg((TasksArg_def)lily_do, s);
	lily_do(s);
#ifdef for_show_detial
	lily_out(s);
	lily_out(">");
#endif // for_show_detial

	return 0;
}
// delete
// for_cmd_lines->content,for_cmd_lines,scopy,iter_field

int32_t end_for()
{
	int32_t i, n;
	n = for_cmd_lines->count;
	str *ss = (str *)(for_cmd_lines->content);
	for (i = 0; i < n; i++)
	{
		free(ss[i]);
	}
	delete_list(for_cmd_lines);
	for_cmd_lines = NULL;
	if (if_stack_count + loop_stack_count + for_stack_count == 1)
	{
		if (scopy)
			delete_li_string(scopy);
		scopy = NULL;
		resume_cmd_stream();
		// lily_is_busy = 0;
	}

	if (*need_delete_field)
	{
		cmd_delete(1, (char **)(&(iter_field->name)));
		iter_field = NULL;
		need_delete_field = NULL;
	}
	// lily_hooks_cmd_done = NULL;
	for_stack_count--; // pop area
	update_for_area();
	invoke_listener;
	if (have_listener)
	{
		// if (hadTask_(current_listener))
		//{
		//	// lily_out("debug_error 1\n");
		// }
		//  else
		tp_addTask(current_listener); // Notify the listener that the for loop is done
	}
#ifdef for_show_detial
	lily_out("<\n");
#endif // for_show_detial

	return 0;
}
// new scopy
char *get_cmd_line_at(Li_List for_cmd_lines, int32_t at)
{
	if (for_cmd_lines->count == 0)
	{
		return (char *)"";
	}
	str *ss = (str *)(for_cmd_lines->content);
	str s = ss[at];
	if (scopy == NULL)
	{
		scopy = new_li_string_by(s);
	}
	else
	{
		assign_li_string(scopy, s);
	}
	return scopy->str;
}

void update_for_area()
{
	if (for_stack_count > for_stack_len)
	{
		lily_out("error for_stack_count<0\n");
		return;
	}
	ForItem_def *area = for_area_stack + for_stack_count - 1;
	iter_field = area->iter_field;
	var_at = area->var_at;
	for_cmd_lines = area->for_cmd_lines;
	// start_val = &area->start_val;
	end_val = &area->end_val;
	step_val = &area->step_val;
	now_at = &area->now_at;
	be_greater = &area->be_greater;
	need_delete_field = &area->need_delete_field;
}

void release_all()
{
	// cause in end_for()/tp_addTask(current_listener), so must remove all listener before
	_cmd_done_listener_stack_top = 0; // remove all listener
	_stack_top = 0;					 // remove all hijack
	// lily_ui.hijacked = 0;

	for (; for_stack_count > 0; for_stack_count--)
	{
		update_for_area();
		end_for();
	}
}

int32_t cmd_loop_start(int32_t n, char *args[]) // loop 3
{
	if (n < 2)
		return -1;
	// get loop count
	int32_t loop_count_;
	float v = _value_from_string_or_var(args[1]);
	if (!isnan(v))
	{
		loop_count_ = v;
	}
	else
	{
		li_error("bad arg", -2);
	}

	loop_cmd_lines = new_list(sizeof(str), 4);
	if (loop_cmd_lines == NULL)
	{
		li_error("memory out", -4);
	}
	loop_in_filling = 1;
	add_hijack(hijackor_loop_end);
	// create successfully
	// push it to stack
	LoopItem_def *area = loop_area_stack + loop_stack_count;
	area->cmd_lines = loop_cmd_lines;
	area->loop_count = loop_count_;
	loop_stack_count++;
	update_loop_area();

	wait_for_end_count = 1;
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial
	return 0;
}

int32_t hijackor_loop_end(int32_t n, char *args[])
{
	char *s = args[0];
	if (str_equal(args[0], "for") || str_equal(args[0], "loop") || str_equal(args[0], "if") || str_equal(args[0], "while"))
	{
		wait_for_end_count++;
	}
	else if (strcmp(s, "end") == 0)
	{
		wait_for_end_count--;
		if (wait_for_end_count == 0)
		{
			// news
			_lily_is_busy = 1;

			loop_in_filling = 0;
			add_listener(do_loop_loop);
			*loop_now_at = 0;
			str s = get_cmd_line_at(loop_cmd_lines, *loop_now_at);

			// note here hijackor_if_end() hijacked lily, so stack_top==1
			if (_stack_top == 1 && str_equal(s, "break"))
			{
				if (go_break() < 0)
				{
					lily_out("[for.c/hijackor_loop_end at 490]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			else if (_stack_top == 1 && str_equal(s, "continue"))
			{
				if (go_continue() < 0)
				{
					lily_out("[for.c/hijackor_for_end at 229]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			tp_addTaskArg((TasksArg_def)lily_do, s);
#ifdef for_show_detial
			lily_out(s);
			lily_out(">");
#endif // for_show_detial

			return Lily_cmd_do_not_notify; // free hijack, not notify
		}
	}
	// save the cmd lines
	char *si = new_string_by(s);
	if (si == NULL || li_add(loop_cmd_lines, si) < 0)
	{
		lily_out("loop error:mry\n");
		_fun_exit();
		return -4;
	}
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial

	return KeepHijack; // notify
}

int32_t do_loop_loop()
{
	if (loop_in_filling)
	{
		loop_stack_count--; // switch last area
		update_loop_area();
	}

	if (++*loop_now_at >= loop_cmd_lines->count)
	{
		*loop_now_at = 0;
		(*loop_count)--;
		if (*loop_count == 0)
		{
			end_loop();
			return 0;
		}
	}

	str s = get_cmd_line_at(loop_cmd_lines, *loop_now_at);
	if (loop_in_filling)
	{
		loop_stack_count++;
		update_loop_area(); // switch back
	}
	if (!_stack_top && str_equal(s, "break"))
	{
		if (go_break() < 0)
		{
			lily_out("[for.c/do_loop_loop at 517]:unknown");
		}
		return 0;
	}
	else if (!_stack_top && str_equal(s, "continue"))
	{
		if (go_continue() < 0)
		{
			lily_out("[for.c/hijackor_for_end at 229]:unknown");
		}
		return 0;
	}

	// addTaskArg((TasksArg_def)lily_do, s);
	lily_do(s);
#ifdef for_show_detial
	lily_out(s);
	lily_out(">");
#endif // for_show_detial

	return 0;
}
void end_loop()
{
	int32_t i, n;
	n = loop_cmd_lines->count;
	str *ss = (str *)(loop_cmd_lines->content);
	for (i = 0; i < n; i++)
	{
		free(ss[i]);
	}
	delete_list(loop_cmd_lines);
	loop_cmd_lines = NULL;
	if (if_stack_count + loop_stack_count + for_stack_count == 1)
	{
		if (scopy)
			delete_li_string(scopy);
		scopy = NULL;
		// lily_is_busy = 0;
		resume_cmd_stream();
	}

	// lily_hooks_cmd_done = NULL;
	loop_stack_count--; // pop area
	update_loop_area();
	invoke_listener;
	// if (have_listener)
	// 	tp_addTask(current_listener); //Notify the listener that the for loop is done
	if (have_listener)
	{
		tp_addTask(current_listener); // Notify the listener that the for loop is done
	}
#ifdef for_show_detial
	lily_out("<\n");
#endif // for_show_detial
}
void update_loop_area()
{
	LoopItem_def *area = loop_area_stack + loop_stack_count - 1;
	loop_count = &area->loop_count;
	loop_cmd_lines = area->cmd_lines;
	loop_now_at = &(area->now_at);
}

void release_all_loops()
{
	_cmd_done_listener_stack_top = 0; // remove all listener
	_stack_top = 0;					 // remove all hijack
	// lily_ui.hijacked = 0;
	for (; loop_stack_count > 0; loop_stack_count--)
	{
		update_loop_area();
		end_loop();
	}
}

void _fun_exit()
{
	release_all();
	release_all_loops();
	release_all_if();
}

// no space
// block:exp1>=exp2
// like !1>2, a=b, !a>=b, a!=b
//  a
//  return 0/1, -1 if error
int32_t calculate_logical_expression(char *exp)
{
	int32_t logical_not = 0;

	while (*exp == '!')
	{
		logical_not = !logical_not;
		exp++;
	}
	int32_t ind = str_index(exp, '>');
	if (ind < 0)
		ind = str_index(exp, '<');
	if (ind < 0)
		ind = str_index(exp, '!'); // note !=, ! must before =
	if (ind < 0)
		ind = str_index(exp, '=');

	if (ind < 0) // no operator
	{
		float a = _cal_delegate(exp);
		if (isnan(a))
			return -631;
		if (logical_not)
			return !a;
		if (a != 0)
			return 1;
		return 0;
	}

	int32_t operator= exp[ind];
	exp[ind] = '\0';
	if (exp[ind + 1] == '=') // >=
	{
		operator|= 0x1000; // add a sign for =
		ind++;
	}
	// a = exp, b=exp+ind+1
	float a = _cal_delegate(exp);
	if (isnan(a))
		return -630;
	float b = _cal_delegate(exp + ind + 1);
	if (isnan(b))
		return -633;
	int32_t result = -634;
	switch (operator)
	{
	case '>':
		result = a > b;
		break;
	case '<':
		result = a < b;
		break;
	case '=':
		result = a == b;
		break;
	case '!':
		result = a != b;
		break;
	case ('>' | 0x1000):
		result = a >= b;
		break;
	case '<' | 0x1000:
		result = a <= b;
		break;
	case '=' | 0x1000:
		result = a == b;
		break;
	case '!' | 0x1000:
		result = a != b;
		break;
	default:
		return -656;
		//		break;
	}
	if (logical_not)
		return !result;

	return result;
}

// no space
// block1 & block2
// block1 | block2
//  a>b & c>d
//  or a>b
// return -1 if error
int32_t combine_logical_expression(char *exp)
{
	int32_t ind = str_index(exp, '&');
	if (ind < 0)
		ind = str_index(exp, '|');
	if (ind < 0) // no and\or operator
	{
		return calculate_logical_expression(exp);
	}
	char operator= exp[ind];
	exp[ind] = '\0';
	int32_t a;
	a = calculate_logical_expression(exp);
	if (a < 0)
		return a;
	int32_t b;
	b = calculate_logical_expression(exp + ind + 1);
	if (b < 0)
		return b;

	if (operator== '&')
		return a && b;
	else
		return a || b;
}

// note in-place operation
int32_t _more_combine_logical(char *exp)
{
	int32_t now_index;
	int32_t left_brace_count = 0;
	int32_t a;
	char operator;
	int32_t logical_not = 0;
	int32_t result;

	for (now_index = 0; exp[now_index] != '\0'; now_index++)
	{
		operator= exp[now_index];
		if (operator== '(')
		{
			left_brace_count++;
			continue;
		}
		if (operator== ')')
		{
			left_brace_count--;
			continue;
		}

		if (!left_brace_count && (operator== '&' || operator== '|'))
		{
			break;
		}
	}
	// only one(-combined) block
	if (exp[now_index] == '\0') // like !(b1|b2)
	{
		if (exp[now_index - 1] == ')')
		{
			exp[now_index - 1] = '\0';
			while (*exp == '!')
			{
				logical_not = !logical_not;
				exp++;
			}
			if (*exp != '(')
			{
				li_error("[lily_for.c,line 759]:brace not match", -759);
			}
			exp++;
			a = _more_combine_logical(exp);
			if (a < 0)
				return a;
		}
		else // b1, like !1>2
		{
			return calculate_logical_expression(exp);
		}
		if (logical_not)
			return !a;
		return a;
	}
	else
	{
		// (b1&b2)|bn
		exp[now_index] = '\0';
		a = _more_combine_logical(exp);
		if (a < 0)
			return a;
	}
	while (1)
	{
		int32_t b_index_from = now_index + 1;
		int32_t b; // find next block
		char next_operator;
		for (logical_not = 0, now_index++; exp[now_index] != '\0'; now_index++)
		{
			next_operator = exp[now_index];
			if (next_operator == '(')
			{
				left_brace_count++;
				continue;
			}
			if (next_operator == ')')
			{
				left_brace_count--;
				continue;
			}
			if (!left_brace_count && (next_operator == '&' || next_operator == '|'))
			{
				break;
			}
		}
		next_operator = exp[now_index];
		exp[now_index] = '\0';
		b = _more_combine_logical(exp + b_index_from);
		if (b < 0)
			return b;
		if (operator== '&')
			result = a && b;
		else
			result = a || b;

		if (next_operator == '\0')
			return result;
		a = result;
		operator= next_operator;
	}
	//	return -814;
}

int32_t cmd_if_start(int32_t n, char *args[]) // if exp
{
	if (n < 2)
		return -1;

	meet_current_exp = _more_combine_logical(args[1]);
	if (meet_current_exp < 0)
	{
		li_error("expression error", -__LINE__);
	}
	// switch context
	if_in_filling = 1;
	For_enrty_t *area = if_area_stack + if_stack_count;
	area->cmd_lines = NULL;
	area->now_at = 0;
	add_hijack(hijackor_if_end);
	wait_for_end_count = 1;
	recive_done = 0;
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial
	return 0;
}

int32_t hijackor_if_end(int32_t n, char *args[])
{
	if_stack_count++; // switch to current context to save cmds
	// push stack, and hijack
	if (if_stack_count >= if_stack_len)
	{
		if_stack_count--;
		lily_out("IF stack overflow\n");
		return -900;
	}
	update_if_area();

	char *s = args[0];
	if (str_equal(args[0], "for") || str_equal(args[0], "loop") || str_equal(args[0], "if") || str_equal(args[0], "while"))
	{
		wait_for_end_count++;
	}
	else if (str_equal(s, "end"))
	{
		wait_for_end_count--;
		if (wait_for_end_count == 0)
		{
			// no exp met, nothing did
			if (if_cmd_lines == NULL)
			{
				// the following are similiar to end_if();
				if_stack_count--; // pop area
				update_if_area();
				// if (have_listener), cause still in hijack, let lily notify the listener
				// 	tp_addTask(current_listener); //Notify the listener that the for loop is done
#ifdef for_show_detial
				lily_out("<\n");
#endif					  // for_show_detial
				return 0; // free hijack
			}
			_lily_is_busy = 1;

			if_in_filling = 0;
			recive_done = 1;
			add_listener(do_if_loop); // remove this after finish

			// start exec cmds
			*if_now_at = 0;
			str s = get_cmd_line_at(if_cmd_lines, *if_now_at);
			// note here hijackor_if_end() hijacked lily, so stack_top==1
			if (_stack_top == 1 && str_equal(s, "break"))
			{
				if (go_break() < 0)
				{
					lily_out("[for.c/hijackor_if_end at 517]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			else if (_stack_top == 1 && str_equal(s, "continue"))
			{
				if (go_continue() < 0)
				{
					lily_out("[for.c/hijackor_if_end at 517]:unknown");
				}
				return Lily_cmd_do_not_notify;
			}
			tp_addTaskArg((TasksArg_def)lily_do, s);
#ifdef for_show_detial
			lily_out(s);
			lily_out(">");
#endif									   // for_show_detial
			return Lily_cmd_do_not_notify; // free hijack, not notify
		}
	}

	if (recive_done)
	{
		if (if_stack_count)
		{
			if_stack_count--;
			update_if_area();
		} // pop to last context
		return KeepHijack;
	}
	if (wait_for_end_count == 1) // in current block
	{
		if (str_equal(s, "elif"))
		{
			if (meet_current_exp) // in block, end if
			{
				meet_current_exp = 0;
				recive_done = 1;
			}
			else
			{
				str_wrap(args[0] + 4, ' ');
				meet_current_exp = _more_combine_logical(args[0] + 4);
				if (meet_current_exp < 0)
				{
					end_if();
					li_error("expression error", -__LINE__);
				}
			}

			if (if_stack_count)
			{
				if_stack_count--;
				update_if_area();
			} // pop to last context
			return KeepHijack;
		}
		else if (str_equal(s, "else"))
		{
			if (meet_current_exp) // if already in a valid block, no need to save more cmds
			{
				recive_done = 1;
				meet_current_exp = 0;
			}
			else
				meet_current_exp = 1; // yet not be caught, using else block
			if (if_stack_count)
			{
				if_stack_count--;
				update_if_area();
			} // pop to last context

			return KeepHijack;
		}
	}

	if (!meet_current_exp)
	{
		if (if_stack_count)
		{
			if_stack_count--;
			update_if_area();
		} // pop to last context
		return KeepHijack;
	}

	// save the cmd lines
	if (if_cmd_lines == NULL)
	{
		if_cmd_lines = new_list(sizeof(str), 1);
		if (if_cmd_lines == NULL)
		{
			lily_out("mem error\n");
			end_if(); // pop stack
			return -938;
		}
		if_area_stack[if_stack_count - 1].cmd_lines = if_cmd_lines;
	}
	char *si = new_string_by(s);
	if (si == NULL || li_add(if_cmd_lines, si) < 0)
	{
		lily_out("mem error,stop running\n");
		_fun_exit();
		return -996;
	}
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial

	if (if_stack_count)
	{
		if_stack_count--;
		update_if_area();
	}				   // pop to last context
	return KeepHijack; // notify
}

int32_t do_if_loop()
{
	if (++*if_now_at >= if_cmd_lines->count)
	{
		// *loop_now_at = 0;
		// (*loop_count)--;
		// if (*loop_count == 0)
		// {
		end_if();
		return 0;
		// }
	}

	str s = get_cmd_line_at(if_cmd_lines, *if_now_at);
	// if (if_in_filling)
	// {
	// 	if_stack_count++;
	// 	update_if_area(); //switch back
	// }

	if (!_stack_top && str_equal(s, "break"))
	{
		if (go_break() < 0)
		{
			lily_out("[for.c/do_loop_loop at 517]:unknown");
		}
		return 0;
	}
	else if (!_stack_top && str_equal(s, "continue"))
	{
		if (go_continue() < 0)
		{
			lily_out("[for.c/do_loop_loop at 517]:unknown");
		}
		return 0;
	}

	// addTaskArg((TasksArg_def)lily_do, s);
	lily_do(s);
#ifdef for_show_detial
	lily_out(s);
	lily_out(">");
#endif // for_show_detial

	return 0;
}

void end_if()
{
	int32_t i, n;
	if (if_cmd_lines != NULL)
	{
		n = if_cmd_lines->count;
		str *ss = (str *)(if_cmd_lines->content);
		for (i = 0; i < n; i++)
		{
			free(ss[i]);
		}
		delete_list(if_cmd_lines);
		if_cmd_lines = NULL;
	}

	if (if_stack_count + loop_stack_count + for_stack_count == 1)
	{
		if (scopy)
			delete_li_string(scopy);
		scopy = NULL;
		// lily_is_busy = 0;
		resume_cmd_stream();
	}

	// lily_hooks_cmd_done = NULL;
	if_stack_count--; // pop area
	update_if_area();
	invoke_listener;
	// if (have_listener)
	// 	tp_addTask(current_listener); //Notify the listener that the for loop is done
	if (have_listener)
	{
		tp_addTask(current_listener); // Notify the listener that the for loop is done
	}
#ifdef for_show_detial
	lily_out("<\n");
#endif // for_show_detial
}

void update_if_area()
{
	if (if_stack_count <= 0)
	{
		if_cmd_lines = NULL;
		if_now_at = NULL;
		return;
	}
	For_enrty_t *area = if_area_stack + if_stack_count - 1;
	// loop_count = &area->loop_count;
	if_cmd_lines = area->cmd_lines;
	if_now_at = &(area->now_at);
}

void release_all_if()
{
	_cmd_done_listener_stack_top = 0; // remove all listener
	_stack_top = 0;					 // remove all hijack
	// lily_ui.hijacked = 0;
	for (; if_stack_count > 0; if_stack_count--)
	{
		update_if_area();
		end_if();
	}
}

// work in do_xx_loop
int32_t go_break()
{
	if (!have_listener)
		return -1;
	// got out from IF blocks first
	while (have_listener && current_listener == do_if_loop)
	{
		end_if();
		// cause in end_if(), the listener may been notified
		if (have_listener)
		{
			int32_t new_add_task_ind = _tp_rear;
			if (new_add_task_ind == 0)
				new_add_task_ind = Tasks_LEN - 1;
			else
				new_add_task_ind--;
			if (_tp_tasks_[new_add_task_ind] == current_listener)
			{
				_tp_rear = new_add_task_ind;
			}
			// else error
		}
	}
	if (!have_listener)
		return -2;

	// int32_t end_loop, it will notify the next listner
	if (current_listener == do_loop_loop)
	{
		end_loop();
	}
	else if (current_listener == do_for_loop)
	{
		end_for();
	}
	else if (current_listener == do_while_loop)
	{
		end_if();
	}
	return 0;
}

int32_t go_continue()
{
	if (!have_listener)
		return -1;
	// got out from IF blocks first
	while (have_listener && current_listener == do_if_loop)
	{
		end_if();
		// cause in end_if(), the listener may been notified
		if (have_listener)
		{
			int32_t new_add_task_ind = _tp_rear;
			if (new_add_task_ind == 0)
				new_add_task_ind = Tasks_LEN - 1;
			else
				new_add_task_ind--;
			if (_tp_tasks_[new_add_task_ind] == current_listener)
			{
				_tp_rear = new_add_task_ind;
			}
			// else error
		}
	}
	if (!have_listener)
		return -1;

	if (current_listener == do_for_loop)
	{
		float start_val = 0.0f;
		int32_t vi;
		*now_at = -1; //
		// *start_val += *step_val;
		switch (iter_field->type)
		{
		case 'f':
			assign_f_from_void(start_val, get_value_of_var(iter_field, var_at));
			start_val += *step_val;
			set_value_of_var(iter_field, var_at, to_voidf(start_val));
			// *(float *)(iter_field->ref) += *step_val;
			// start_val = *(float *)(iter_field->ref);
			break;
		case 'd':
		case 'c':
			vi = (int32_t)get_value_of_var(iter_field, var_at);
			vi += *step_val; // abs(step_val)>1
			if (set_value_of_var(iter_field, var_at, to_void(vi)) < 0)
			{
				lily_out("[for_loop.c/do_for_loop]:assign failed");
			}

			// *(int32_t *)(iter_field->ref) += *step_val;
			start_val = vi; //*(int32_t *)(iter_field->ref);
			break;

		default:
			break;
		}

		if ((*be_greater && start_val >= *end_val) || (!*be_greater && start_val <= *end_val)) // iteration end
		{
			end_for();
			// return 0;
		}
		else
		{
			if (have_listener)
			{
				// if (hadTask_(current_listener))
				//{
				//	// lily_out("debug_error 4\n");
				// }
				//  else
				tp_addTask(current_listener); // Notify the listener that the for loop is done
			}
			// if (have_listener)
			// 	tp_addTask(current_listener); //Notify
		}
	}
	else if (current_listener == do_loop_loop)
	{
		*loop_now_at = -1; // note here, cause  if (++*loop_now_at >= loop_cmd_lines->count)
		(*loop_count)--;
		if (*loop_count == 0)
		{
			end_loop();
			// return 0;
		}
		else
		{
			// if (have_listener)
			// 	tp_addTask(current_listener); //Notify
			if (have_listener)
			{
				// if (hadTask_(current_listener))
				//{
				//	// lily_out("debug_error 5\n");
				// }
				//  else
				tp_addTask(current_listener); // Notify the listener that the for loop is done
			}
		}
	}
	else if (current_listener == do_while_loop)
	{
		*if_now_at = 0;
		str s = get_cmd_line_at(if_cmd_lines, *if_now_at);
		meet_current_exp = _more_combine_logical(s);
		if (meet_current_exp < 0)
		{
			_fun_exit();
			li_error("expression error", -__LINE__);
			//			return 0;
		}
		if (!meet_current_exp) // not met, break
		{
			end_if();
			return 0;
		}
		// still true
		// *if_now_at++; //from the first cmd,==1
		notify_listener(); // by manually
	}

	return 0;
}

// new made for while(exp)

// maybe WHILE and IF block can use the same stack,
// cause they have same properities to save
// char whle_stack_count = 0;
// Li_List while_cmd_lines = NULL;
// int32_t *if_now_at = NULL;

int32_t cmd_while_start(int32_t n, char *args[]) // if exp
{
	if (n < 2)
		return -1;
	char tx[TX_len];
	joint_args(n - 1, args + 1);
	str_wrap(args[1], ' ');
	strcpy(tx, args[1]);
	meet_current_exp = _more_combine_logical(tx);
	if (meet_current_exp < 0)
	{
		li_error("expression error", -__LINE__);
	}
	if (meet_current_exp) // while true
	{
		// start recording
		if_cmd_lines = new_list(sizeof(str), 2);
		if (if_cmd_lines == NULL)
		{
			lily_out("mem error\n");
			return -1496;
		}
		char *si = new_string_by(args[1]);
		if (si == NULL || li_add(if_cmd_lines, si) < 0)
		{
			lily_out("mem error,stop running\n");
			_fun_exit();
			return -1540;
		}
	}
	// switch context
	if_in_filling = 1;
	For_enrty_t *area = if_area_stack + if_stack_count;
	area->cmd_lines = if_cmd_lines;
	area->now_at = 0;

	add_hijack(hijackor_while_end);
	wait_for_end_count = 1;
	// recive_done = 0;
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial
	return 0;
}

int32_t hijackor_while_end(int32_t n, char *args[])
{
	if_stack_count++;
	// push stack, and hijack
	if (if_stack_count >= if_stack_len)
	{
		if_stack_count--;
		lily_out("WHILE stack overflow\n");
		return -900;
	}
	update_if_area();

	char *s = args[0];
	if (str_equal(args[0], "for") || str_equal(args[0], "loop") || str_equal(args[0], "if") || str_equal(args[0], "while"))
	{
		wait_for_end_count++;
	}
	else if (str_equal(s, "end"))
	{
		wait_for_end_count--;
		if (wait_for_end_count == 0)
		{
			if (if_cmd_lines == NULL)
			{
				if_stack_count--; // pop area
				update_if_area();
#ifdef for_show_detial
				lily_out("<\n");
#endif					  // for_show_detial
				return 0; // free hijack, and notify
			}
			else if (if_cmd_lines->count == 1)
			{
				// cause it will invoke listener in end_if(), so add one in dummy
				add_listener(do_while_loop);
				end_if(); // it will notify listener
				return Lily_cmd_do_not_notify;
			}

			_lily_is_busy = 1;
			if_in_filling = 0;
			// recive_done = 1;
			add_listener(do_while_loop); // remove this after finish
			// start exec cmds
			*if_now_at = 0;
			// notify_listener();// who is do_while_loop

#ifdef for_show_detial
			lily_out(s);
			lily_out(">");
#endif				  // for_show_detial
			return 0; // Notify and free hijack
		}
	}
	if (!meet_current_exp)
	{
		if (if_stack_count)
		{
			if_stack_count--;
			update_if_area();
		} // pop to last context
		return KeepHijack;
	}
	char *si = new_string_by(s);
	if (si == NULL || li_add(if_cmd_lines, si) < 0)
	{
		lily_out("mem error,stop running\n");
		_fun_exit();
		return -__LINE__;
	}
#ifdef for_show_detial
	lily_out(":");
#endif // for_show_detial
	if (if_stack_count)
	{
		if_stack_count--;
		update_if_area();
	}				   // pop to last context
	return KeepHijack; // notify
}

int32_t do_while_loop()
{
	if (++*if_now_at >= if_cmd_lines->count)
	{
		*if_now_at = 0;
		str s = get_cmd_line_at(if_cmd_lines, *if_now_at);
		meet_current_exp = _more_combine_logical(s);
		if (meet_current_exp < 0)
		{
			_fun_exit();
			li_error("expression error", -__LINE__);
		}
		if (!meet_current_exp) // not met, break
		{
			end_if();
			return 0;
		}
		// still true
		++*if_now_at; // from the first cmd,==1
	}

	str s = get_cmd_line_at(if_cmd_lines, *if_now_at);

	if (!_stack_top && str_equal(s, "break"))
	{
		if (go_break() < 0)
		{
			lily_out("[for.c/do_loop_loop at 517]:unknown");
		}
		return 0;
	}
	else if (!_stack_top && str_equal(s, "continue"))
	{
		if (go_continue() < 0)
		{
			lily_out("[for.c/do_loop_loop at 517]:unknown");
		}
		return 0;
	}
	lily_do(s);
#ifdef for_show_detial
	lily_out(s);
	lily_out(">");
#endif // for_show_detial

	return 0;
}

void controlSentences_init()
{
#define new_cmd2(name, func, help_doc)                \
	{                                                 \
		public_a_cmd_link_doc(#name, func, help_doc); \
	}

		new_cmd2(for, cmd_for_start, "forLoops\nfor i=a:s:b\ncmds\nend");
		new_cmd2(loop, cmd_loop_start, "flow control\nloop n\ncmds\nend");
		new_cmd2(if, cmd_if_start, "logical control\nif exp\ncmds\nelif exp\ncmds\nelse\ncmds\nend");
		new_cmd2(while, cmd_while_start, "logical control\nwhile exp\ncmds\nend");
#undef new_cmd2
}
/* test script
a=10
while 1
a=a-1
if a=5
break
end
end

*/